/*
* 函数组合概念
* 纯函数和柯里化很容易写出洋葱代码
* 例如：获取数组的最后一个元素再转换成大写字母
*/

_.toUpper(_.first(_.reverse(array)))

/*
管道：就是对输入进行处理，再输出，中间过程可以看作一个管道
当函数比较复杂的时候，可以把fn拆分成多个小函数

函数组合：compose 如果一个函数要经过多个函数处理才能得到最终值，这个时候可以把中间过程的函数合并成一个函数
   函数组合默认是从右到左执行的
*/

function compose(f, g) {
    return function(value) {
        return f(g(value))
    }
}
function reverse (array) {
    return array.reverse()
}
function first (array) {
    return array[0]
}
/*
* 获取数组的最后一个元素
* 反转数组
* 获取第一个元素
*/
const last = compose(first, reverse) 
console.log(last([1,2,3,4]))


// lodash 中的函数组合的方法 _.flowRight()
const reverse = arr => arr.reverse()
const first = arr => arr[0]
const toUpper = s => s.toUpperCase();
const f = _.flowRight(toUpper, first, reverse)


//组合函数的原理模拟

// reduce 
function compose(...args) {
    return function (value){
      return args.reverse().reduce(function(acc, fn){
        return fn(acc)
      }, value)
    }
  }
  
// 简化
const compose = (...args) => value => args.reverse().reduct((acc, fn) => fn(acc),value)

// 函数组合-结合律 => 既可以把g和h组合，还可以把f和g组合，结果都是一样的
let f = compose(f, g, h)
let associative = compose(compose(f, g), h) == compose(f, compose(h, g))

const f = _.flowRight(_.toUpper, _.first, _.reverse);
const f = _.flowRight(_.flowRight(_.toUpper, _.first), _.reverse)
const f = _.flowRight(_.reverse, _.flowRight(_.toUpper, _.first))

// 函数组合-调试
// NEVER SAY DIE ==> never-say-die
const log = v => {
    console.log(v)
    return v
}
// 改造log
const trace = _.curry((tag, v) => {
    console.log(tag, v)
    return v
})

// _.split()
const split = _.curry((sep, str) => _.split(str, sep))
// _.toLower()
const join = _.curry((sep, str) => _.join(array, sep))
const map = _.curry((fn, array)=>_.map(array, fn))

const f = _.flowRight(join('-'), log, map(_.toLoewe), split(' '))
const f = _.flowRight(join('-'), trace('map  after'), map(_.toLoewe), trace('split after') ,split(' '))